package com.diaohw.module.system.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjUtil;
import com.diaohw.module.system.mapper.AccountMapper;
import com.diaohw.module.system.mapper.RoleMapper;
import com.diaohw.module.system.obj.dto.AccountInsertDto;
import com.diaohw.module.system.obj.dto.AccountUpdateDto;
import com.diaohw.module.system.obj.entity.Account;
import com.diaohw.module.system.obj.entity.AccountRole;
import com.diaohw.module.system.obj.entity.Role;
import com.diaohw.module.system.obj.mapstruct.AccountMapstruct;
import com.diaohw.module.system.obj.mapstruct.RoleMapstruct;
import com.diaohw.module.system.obj.query.AccountQuery;
import com.diaohw.module.system.obj.vo.AccountVo;
import com.diaohw.module.system.obj.vo.RoleVo;
import com.diaohw.module.system.service.AccountRoleService;
import com.diaohw.module.system.service.AccountService;
import com.diaohw.platform.common.obj.page.PageResultVo;
import com.diaohw.platform.common.util.CryptoUtil;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * <p>
 * 用户 服务实现类
 * </p>
 *
 * @author D-Hw
 * @since 2024-07-05
 */
@Service
public class AccountImpl implements AccountService {

    @Resource
    private RoleMapper roleMapper;
    @Resource
    private AccountMapper accountMapper;

    @Resource
    private AccountRoleService accountRoleService;

    @Override
    @Caching
    public AccountVo create(AccountInsertDto data) {
        Account model = AccountMapstruct.INSTANCE.dtoToEntity(data);

        model.setSalt(IdUtil.randomUUID());
        String password = CryptoUtil.md5(model.getSalt(), model.getPassword());
        model.setPassword(password);
        accountMapper.insert(model);
        accountRoleService.resetRole(model.getId(), data.getRoleId());
        return AccountMapstruct.INSTANCE.entityToVo(model);
    }

    @Override
    public AccountVo update(String id, AccountUpdateDto data) {
        Account model = AccountMapstruct.INSTANCE.dtoToEntity(data);
        model.setId(id);
        accountMapper.update(model);

        accountRoleService.resetRole(model.getId(), data.getRoleId());

        return AccountMapstruct.INSTANCE.entityToVo(model);
    }

    @Override
    public Boolean delete(String id) {
        accountRoleService.resetRole(id, List.of());
        return accountMapper.deleteById(id) > 0;
    }


    @Override
    public List<AccountVo> findByList(AccountQuery query) {
        QueryWrapper wrapper = AccountMapper.createWrapper(query);
        List<Account> list = accountMapper.selectListByQuery(wrapper);
        return convert(list);
    }

    @Override
    public PageResultVo<AccountVo> findByPage(AccountQuery query) {
        QueryWrapper wrapper = AccountMapper.createWrapper(query);
        com.mybatisflex.core.paginate.Page<Account> page = accountMapper.paginate(query.getPageIndex(), query.getPageSize(), wrapper);
        List<AccountVo> convert = convert(page.getRecords());
        return PageResultVo.create(page.getTotalRow(), convert);

    }

    @Override
    public AccountVo detail(String id) {
        Account model = accountMapper.selectOneById(id);
        return AccountMapstruct.INSTANCE.entityToVo(model);
    }

    private List<AccountVo> convert(List<Account> models) {
        if (models.isEmpty()) {
            return List.of();
        }

        List<String> accountIds = models.stream().map(Account::getId).toList();
        List<AccountRole> accountRoles = accountRoleService.list(accountIds);

        List<AccountVo> records = models.stream().map(AccountMapstruct.INSTANCE::entityToVo).toList();
        List<String> roleIds = accountRoles.stream().map(AccountRole::getRoleId).toList();
        if (roleIds.isEmpty()) {
            return records;
        }
        List<Role> roles = roleMapper.selectListByIds(roleIds);
        if (roles.isEmpty()) {
            return records;
        }
        Map<String, List<String>> accountRoleMap = accountRoles.stream().collect(Collectors.groupingBy(AccountRole::getAccountId, Collectors.mapping(AccountRole::getRoleId, Collectors.toList())));

        Map<String, RoleVo> roleMap = RoleMapstruct.INSTANCE.entityToVo(roles).stream().collect(Collectors.toMap(RoleVo::getId, e -> e));

        records.stream().filter(ObjUtil::isNotNull).filter(account -> accountRoleMap.containsKey(account.getId())).forEach(record -> {
            String roleName = accountRoleMap.get(record.getId()).stream()
                    .filter(roleMap::containsKey)
                    .map(roleMap::get)
                    .map(RoleVo::getRoleName)
                    .collect(Collectors.joining(","));
            record.setRoleName(roleName);

            String roleCode = accountRoleMap.get(record.getId()).stream()
                    .filter(roleMap::containsKey)
                    .map(roleMap::get)
                    .map(RoleVo::getRoleCode)
                    .collect(Collectors.joining(","));
            record.setRoleCode(roleCode);
            record.setRoleId(accountRoleMap.get(record.getId()));
        });

        return records;
    }


}
